import React, { useContext,createContext, useMemo } from "react";
import { LibAppView  } from "../../../lib";

interface IAdminApi {
    goto: (key: string, option?: AppView.IApplicationGotoOption) => void;
    registeJourney: (data: AppView.IJourney) => Function;
}

interface ICreateApi<IApi={}> {
    createProvider: (overrideApi: Partial<IApi>) => React.ComponentType<any>;
    Provider: React.ComponentType<any>;
    useApi: () => IAdminApi & IApi;
}


const ApiContext = createContext<any>({});
const ApiExContext = createContext({});

export const ApiProvider = ({ children }: any) => {
    const app = LibAppView.useApp();
    const microApp = LibAppView.useMicroApp();
    const apiContext = useMemo(() => ({
        goto: (key: string, state?: any) => app.goto(key, state),
        registeJourney: (data: AppView.IJourney) => microApp.registeJourney(data)
    }), []);
    return <ApiContext.Provider value={apiContext}>{children}</ApiContext.Provider>;
};

const createApiProvider = <IApi={}>(exApi: IApi) => ({ children }: any) => {
    const adminApi = useContext(ApiContext);
    const prevApi = useContext(ApiExContext);
    const nextApi = useMemo(() => {
        const prevApiKeys = Object.keys(prevApi);
        const adminApiKeys = Object.keys(adminApi);
        const nextExApi: any = {};

        Object.keys(exApi as any).forEach((name: string) => {
            if(!prevApiKeys.includes(name) && !adminApiKeys.includes(name)) {
                nextExApi[name] = (exApi as any)[name];
            } else {
                console.error(`定义API重复。(name: ${name})`);
            }
        });
        return {
            ...prevApi,
            ...nextExApi
        };
    }, [prevApi]);
    return <ApiExContext.Provider value={nextApi}>{children}</ApiExContext.Provider>
};

export const createApi = <IApi={}>(exApi: IApi): ICreateApi<IApi> => {
    
    const createProvider = (override: any = {}) => {
        Object.keys(exApi as any).forEach((name) => {
            if(override[name] && typeof (exApi as any)[name] === "function") {
                const overrideMethod = (exApi as any)[name](override[name]);
                (exApi as any)[name] = overrideMethod;
            }
        });
        return createApiProvider(exApi);
    }
    return {
        createProvider,
        Provider: createApiProvider(exApi),
        useApi: () => {
            const adminApi = useContext(ApiContext);
            const exApi = useContext(ApiExContext);
            return useMemo(() => ({
                ...adminApi,
                ...exApi
            }), [adminApi, exApi]);
        }
    }
};